/*
 * MainFrame.cpp
 *
 *  Created on: 15 Nov 2013
 *      Author: axel
 */

#include "MainFrame.h"

#include <iostream>
#include <stdlib.h>
#include <GL/glew.h>
#include <glfw3.h>
#include <ctime>


const int MainFrame::WIDTH = 800;
const int MainFrame::HEIGHT = 600;
const char* MainFrame::TITLE = "AxeEngine V-1.0";

const double MainFrame::FPS = 60;
int MainFrame::timer = 0;

MainFrame::MainFrame(void)
{
	 running=true;
	 lastFrame = 0;
	 manager = new StateManager();
	 window = NULL;
	 currentState = NULL;
}


MainFrame::~MainFrame(void)
{
}

void MainFrame::gameLoop() {
	init();

	//time in ms, when last updated
	double lastUpdateTime = getTime();
	//average time in ms per frame
	const double TIME = 1000 / FPS;

	//maximum number of updates per frame
	const int MAXSKIP = 1;

	//counts the number of updates
	int loops=0;

	//counter for the actual fps:
	int countFrames=0;
	int renders=0;
	int lastSecondTime = (int) (lastUpdateTime / 1000);

	while (running && !glfwWindowShouldClose(window)) {

		//Update the Game and Handling Input

		loops=0;
		while ((getTime()>lastUpdateTime) && (loops < MAXSKIP)) {
			update();
			handleInput();

			lastUpdateTime += TIME;
			loops++;
			timer++;

			countFrames++;
		}

		// Render the game
		float interpolation = float(getTime() + TIME - lastUpdateTime)/ float( TIME);
		render(interpolation);

		renders++;
		int thisSecond = (int) (lastUpdateTime / 1000);
		if (thisSecond > lastSecondTime){
			std::cout << "NEW SECOND " << thisSecond << " " << countFrames  << " Renders: " << renders << std::endl;
	    	countFrames=0;
			renders=0;
        	lastSecondTime = thisSecond;
		}
	}

	// Dispose any resources and destroy our window
	destroy();
}


/*Will return time in milliseconds*/
long MainFrame::getTime(){
	return clock();
}

void MainFrame::stopLoop(){
	running=false;
}

void MainFrame::init() {
	initWithGLFW();

	currentState = manager->initialiseState();
}

// Error callback function prints out any errors from GFLW to the console
static void error_callback( int error, const char *description ) {
    std::cout << error << '\t' << description << std::endl;
}

void MainFrame::initWithGLFW() {
	glfwSetErrorCallback( error_callback );

	 /* Initialize the library */
    if (!glfwInit()) {
    	std::cout << "error: can't initiate glfw";
    	exit(-1);
	}

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3.3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    //glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
    glfwWindowHint(GLFW_SAMPLES,4);

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(WIDTH, HEIGHT, TITLE, NULL, NULL);
    if (!window) {
    	std::cout << "error opening the glfw window";
        glfwTerminate();
        exit(-1);
    }

	//Needed to use OpenGL
	glfwMakeContextCurrent(window);

	initGlew();
}

void MainFrame::initGlew() {
	glewExperimental=GL_TRUE;
	GLenum res = glewInit();
    if (res) {
      std::cout << "Error: " << glewGetErrorString(res);
      exit(-1);
    }
}

void MainFrame::destroy(){
	glfwTerminate();
}

void MainFrame::render(float interpolation){
	//clears the screen
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//do the rendering
	currentState->renderGame(interpolation);

	/* Swap front and back buffers */
    glfwSwapBuffers(window);
}

void MainFrame::update(){
	//update game positions
	currentState->updateGame(timer);
	if (currentState->stateChanger()!=0){
		changeState(manager->callStates(currentState->stateChanger(), currentState->getKeyCode(), currentState));
	}
}

void MainFrame::handleInput(){
	/* Poll for and process events */
    glfwPollEvents();
	currentState->handleInput(window);
}

void MainFrame::changeState(StateMachine* level){
	currentState = level;
}

void MainFrame::VSyncOn() {
	glfwSwapInterval(1);
}

void MainFrame::VSyncOff() {
	glfwSwapInterval(0);
}
